package com.ssg.poultry.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import com.ssg.poultry.exception.SerialPortException;
import com.ssg.poultry.util.ByteUtil;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

public class SerialPortService{
	private Logger logger = Logger.getLogger(this.getClass());
	//波特率
	private int baudRate;
	@SuppressWarnings("unused")
	private int stopBitNum;
	
	private SerialPortListener listener = null;

	public SerialPortService(int baudRate, int stopBitNum) {
		this.baudRate = baudRate;
		this.stopBitNum = stopBitNum;
	}

	
	public List<CommPortIdentifier> listPort() {
		List<CommPortIdentifier> results = new LinkedList<>();
		@SuppressWarnings("unchecked")
		Enumeration<CommPortIdentifier> all = CommPortIdentifier.getPortIdentifiers();
		while (all.hasMoreElements()) {
			CommPortIdentifier cpid = all.nextElement();
			if (cpid.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				results.add(cpid);
			}
		}
		return results;
	}

	
	public List<String> listPortName() {
		List<String> results = new LinkedList<>();
		@SuppressWarnings("unchecked")
		Enumeration<CommPortIdentifier> all = CommPortIdentifier.getPortIdentifiers();
		while (all.hasMoreElements()) {
			CommPortIdentifier cpid = all.nextElement();
			if (cpid.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				results.add(cpid.getName());
			}
		}
		return results;
	}

	public SerialPort connPort(String name) throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException {

		CommPortIdentifier cpid = CommPortIdentifier.getPortIdentifier(name);

		CommPort commPort = cpid.open(name, 2000);

		if (commPort instanceof SerialPort) {
			SerialPort port = (SerialPort) commPort;
			port.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
			return port;
		}
		return null;
	}

	public void closePort(SerialPort port) {
		if (port != null) {
			port.close();
			port = null;
		}
	}

	public void writeToPort(SerialPort port, byte[] data) throws SerialPortException {
		OutputStream out = null;
		try {
			out = port.getOutputStream();
			logger.debug("srart write:");
			out.write(data);
			logger.debug("write finished , then flush:");
			out.flush();
			onEvent(SerialPortListener.EVENT_WRITE, data);
			logger.debug("flush finished.");
			
			logger.debug("write data :"+ByteUtil.bytesToHex(data));
		} catch (IOException e) {
			e.printStackTrace();
			throw new SerialPortException(SerialPortException.REASON_IO);
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public byte[] readFromPort(SerialPort port) throws SerialPortException {
		InputStream in = null;
		ByteArrayOutputStream data = new ByteArrayOutputStream();
		try {
			in = port.getInputStream();
			int length = in.available();
			while(length > 0) {
				byte[] buffer = new byte[length];
				in.read(buffer);
				data.write(buffer);
				length = in.available();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new SerialPortException(SerialPortException.REASON_IO);
		}
		onEvent(SerialPortListener.EVENT_READ, data.toByteArray());
		logger.debug("read data :"+ByteUtil.bytesToHex(data.toByteArray()));
		return data.toByteArray();
	}
	
	public byte[] readFromPort(SerialPort port,int length) throws SerialPortException {
		InputStream in = null;
		byte[] data = new byte[length];
		try {
			in = port.getInputStream();
			int read = 0;
			while(length > read) {
				int x = in.read(data, read, length-read);
				read += x;
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new SerialPortException(SerialPortException.REASON_IO);
		}
		onEvent(SerialPortListener.EVENT_READ, data);
		logger.debug("read data :"+ByteUtil.bytesToHex(data));
		return data;
	}
	public void writeHex(SerialPort port,String hex) throws SerialPortException {
		hex = hex.replace(" ", "");
		logger.debug("writeHex:"+hex);
		byte[] data = ByteUtil.hexToBytes(hex);
		writeToPort(port, data);
	}
	private void onEvent(String event,byte[] data) {
		if(listener != null) {
			listener.on(event, data);
		}
	}

	public int getBaudRate() {
		return baudRate;
	}
	
	public void setBaudRate(int baudRate) {
		this.baudRate = baudRate;
	}

	public SerialPortListener getListener() {
		return listener;
	}
	
	public void setListener(SerialPortListener listener) {
		this.listener = listener;
	}
	
}
